
# Realiza a contagem de arquivos e linhas de um projeto, fornecendo os totais
# por extensao (.rb, .jsp, .java, etc)
#
# Autor: Cassio Marques (cassiommc@gmail.com)
#
# Este script eh LIVRE. Altere o que quiser, use onde quiser, distribua
# para quem quiser.
# Ninguem ira lhe processar.
# Porem, nao me responsabilizo por nada que aconteca ao seu computador
# ou aos seus arquivos caso voce execute este script.
# Use por sua conta e risco.
require 'find'

file_types = {
  ".jsp"          => "Paginas JSP",
  ".html"         => "Paginas HTML",
  ".xml"          => "Arquivos XML",
  ".java"         => "Arquivos Java",
  ".js"           => "Arquivos Javascript",
  ".css"          => "Arquivos Cascading Style Sheets",
  ".rb"           => "Arquivos Ruby",
  ".properties"   => "Arquivos de propriedades",
  ".sql"          => "Arquivos para banco de dados",
  ".pgsql"        => "Arquivos com stored procedures do PostgreSQL",
  ".cpp"          => "Arquivos fonte em C++",
  ".c"            => "Arquivos fonte em C",
  ".h"            => "Arquivos header C/C++",
  ".jar"          => "Arquivos de biblioteca Java",
  ".py"           => "Arquivos Phyton",
  ".pl"           => "Arquivos Perl",
  ".sh"           => "Arquivos Shell Script",
  ".php"          => "Arquivos PHP",
  ".swf"          => "Arquivos Flash",
  ".rake"         => "Arquivos RAKE",
  ".yml"          => "Arquivos de configuracao YAML",
  ".erb"          => "Templates HTML ERB",
  ".rhtml"        => "Templates RHTML"
}

file_quantities = {}
@loc = {}
@blank = {}
@comments = {}
@unknown_files = 0
@unknown_extensions = {}
@total_files = 0

file_types.keys.each do |k|
  file_quantities[k] = 0
  @loc[k] = 0
  @comments[k] = 0
  @blank[k] = 0
end

def increment_unknown_extensions(ext)
  if @unknown_extensions.include? ext then
    @unknown_extensions[ext] += 1
  else
    @unknown_extensions[ext] = 0
  end
end

def should_list?(f)
  f !~ /doc[s]?\/|documentacao|svn|classes|logs|work/i
end

def increment(hash, ext)
  hash[ext] += 1 unless !hash.include? ext
end

def increment_comments(ext)
  increment(@comments, ext)
end

def increment_blanks(ext)
  increment(@blank, ext)
end

def increment_code(ext)
  increment(@loc, ext)
end

def count_lines(file_name)
  file_name =~ /(.+)(\..+)/i
  ext = $2
  @multiline_comment = false
  @cpp_style = false
  @xml_style = false
  File.new(file_name).each do |line|
    line.strip!
    unless line != ""
      increment_blanks(ext)
      next
    end
    # procurando final do comentario com varias linhas
    if @multiline_comment then
      if (line =~ /\*\/$/ && @cpp_style) || (line =~ /-->$/ && @xml_style) then
        increment_comments(ext)
        @multiline_comment = false
        next
      else
        increment_comments(ext)
        next
      end
    end
    # padroes para comentarios com uma unica linha
    if line =~ /^\/\// ||
       line =~ /^\/\*.+\*\// ||
       line =~ /<!--.+-->/ ||
       (file_name =~ /\.rb|sh|properties$/i && line =~ /^#/) ||
       (file_name =~ /\.pgsql|sql$/i && line=~ /^--/) then
      increment_comments(ext)
      next
    end
    if line =~ /^\/\*/ && !@multiline_comment then
      @multiline_comment = true     # encontrado comentario com varias linhas,
                                    # no formato /*...(linhas)...*/
      @cpp_style = true
      increment_comments(ext)
      next
    end
    if line =~ /^<!--/ && !@multiline_comment then
      @multiline_comment = true     # encontrado comentario com varias linhas,
                                    # no formato <!-- (linhas)... -->
      @xml_style = true
      increment_comments(ext)
    end
    increment_code(ext)
  end
end

if ARGV.length != 1
	puts "Modo de usar: ruby #{$0} caminho_do_projeto"
	Kernel.exit(0)
end

cur_dir = Dir.pwd
Dir.chdir(ARGV[0])

Find.find( './' ) do |f|
  Find.prune if !should_list?(f)
  f =~ /(.+)(\..+)/i
  ext = $2
  #puts "Processando arquivo #{f}..."
  file_quantities[ext] += 1 unless !file_quantities.include? ext
  if !File.directory?(f) && f !~ /~$/ then
     @total_files += 1 if !File.directory?(f)
     if !file_types.include? ext
      @unknown_files += 1
      increment_unknown_extensions(ext)
     end
  end 

  if !File.directory?(f) && f !~ /\.(jar|swf)$/
    count_lines(f)
  end
end

Dir.chdir(cur_dir)

puts "\n===> Estatisticas de <#{ARGV[0]}>:"
file_quantities.each do |k,v|
  puts "*#{file_types[k]} (#{k}) ==> #{v}\n(Codigo:#{@loc[k]} | Comentarios:#{@comments[k]} | Em branco:#{@blank[k]})\n\n" unless file_quantities[k] == 0
end
puts "#{@total_files} arquivos no total, #{@unknown_files} arquivos desconhecidos."
puts "Extensoes desconhecidas encontradas => \n#{@unknown_extensions.keys.join("\n")}" unless @unknown_extensions.empty?
puts "\n"
